home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / zm16src / rz.c < prev    next >
C/C++ Source or Header  |  1988-05-18  |  29KB  |  1,449 lines

  1. /*
  2.  *                ACKNOWLEDGEMENTS
  3.  *
  4.  *    ZMDM was derived from rz/sz for Unix  posted by 
  5.  *    Chuck Forsberg (...!tektronix!reed!omen!caf ). We
  6.  *    thank him for his excellent code, and for giving
  7.  *    us permission to use and distribute his code and
  8.  *    documentation.
  9.  *
  10.  *    Atari St version by:
  11.  *        Jwahar Bammi
  12.  *            usenet: mandrill!bammi@{decvax,sun}.UUCP
  13.  *            csnet:  bammi@mandrill.ces.CWRU.edu
  14.  *            arpa:   bammi@mandrill.ces.CWRU.edu
  15.  *            CompuServe: 71515,155
  16.  */
  17.  
  18. #include "config.h"
  19. #define RVERSION "rz 1.14 01-15-87"
  20. #define RSTVERSION "rz 1.01 03-07-87"
  21. #define OS    "Unix V7/BSD"
  22.  
  23. /* #define RDEBUG */            /* a lot of debugging garb */
  24.  
  25. /*
  26.  *    ATARI ST series implementation notes:
  27.  *
  28.  *        - the following command line options were removed as they
  29.  *          were either  not applicable to the ST environment or
  30.  *          were not deemed reasonable (by me - ofcourse).
  31.  *            1    Not Applicable here as we have a seperate
  32.  *                serial port.
  33.  *            7    In this day and age? Forget it, get another m/c.
  34.  *            a/b    Ascii/Binary - the receive mode (if not
  35.  *                over-ridden by the sender) is automatically
  36.  *                selected depending on the extention given
  37.  *                in the incoming file name. This idea was
  38.  *                present in earlier rz/sz, i wonder why such
  39.  *                a convenient feature was dropped (Chuck ??).
  40.  *                This feature is relevant to ZMODEM only in rz,
  41.  *                as the sender determines the file mode in
  42.  *                XMODEM/YMODEM transfers.
  43.  *                B    Note that `B' has a special meaning.
  44.  *                Specifying -B will force override to
  45.  *                binary mode for each incoming file. Useful
  46.  *                 when doing St-to-St transfers.
  47.  *            D    There is no /dev/null on the ST's
  48.  *            u    not applicable to TOS. Upper and lower
  49.  *                case file names are the same. All the
  50.  *                applicable routines like uncap() and
  51.  *                IsAnyLower() were zapped.
  52.  *
  53.  *        - The    [-][v]rzCOMMAND style of invocation was dropped
  54.  *          as there is no good way to do pipes without the 
  55.  *          microRtx kernal. All references to Pipe and popen()
  56.  *          were zapped.
  57.  *        - Verbose is always set to 2 by automatically, as we know that
  58.  *          stdout != stderr. This can be overridden
  59.  *          by specifying -q to ensure that Verbose = 0
  60.  *        - The idea of a PUBDIR and Restricted paths in the origonal
  61.  *          code  was dropped totally as it is not applicable
  62.  *          to the single owner ST environment. 1 man 1 machine.
  63.  *        - CRCTABLE is default always, hey we have plenty of memory!.
  64.  *        - LOGFILE renamed to 'rzlog/szlog' as we don't always have
  65.  *          a meaningful environment to pick up TMPDIR from (like when
  66.  *          running from the desktop).
  67.  *            - When a subdirectory in an incoming path name is not
  68.  *          present it is created.
  69.  *        - The file mode transmitted is 0S00 where S is derived from
  70.  *          the Read/Write attribute of the file on the ST
  71.  *        - When a file mode is received, only the owner bits are
  72.  *          are checked. If it was read only (r--) on the Unix sytem
  73.  *          then it is given read only attribute on the ST, read-write
  74.  *          otherwise.
  75.  *        - Of course all the I/O was completely redone on the ST.
  76.  *        - You will find two versions of VARARGS routines like log,
  77.  *          one that takes int args, and the other that takes long
  78.  *          (address) args, since sizeof(int) != sizeof(long)
  79.  *          and sizeof(int) != sizeof(pointer) on the ST.
  80.  *
  81.  *    ST v1.01
  82.  *     added support for 32 bit CRC's for Zmodem ++jrb
  83.  *
  84.  *    ST v1.2
  85.  *     added -B ++jrb
  86.  *     added all the recursive stuff
  87.  *     added remote
  88.  */
  89.         
  90. /*% cc -DNFGVMIN -DCRCTABLE -K -O % -o rz; size rz
  91.  *
  92.  * rz.c By Chuck Forsberg
  93.  *
  94.  *    cc -O rz.c -o rz        USG (3.0) Unix
  95.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  96.  *
  97.  *    ln rz rb            For either system
  98.  *
  99.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  100.  *                    login shell. rzrmail then calls
  101.  *                    rmail(1) to deliver mail.
  102.  *
  103.  *        define CRCTABLE to use table driven CRC
  104.  *
  105.  *  Unix is a trademark of Western Electric Company
  106.  *
  107.  * A program for Unix to receive files and commands from computers running
  108.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  109.  *  rz uses Unix buffered input to reduce wasted CPU time.
  110.  *
  111.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  112.  * "COMMAND filename"
  113.  *
  114.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  115.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  116.  *  character reads for these systems. Added 7-01-84 CAF
  117.  *
  118.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  119.  *
  120.  *  NFGVMIN Added 1-13-85 CAF for PC-AT Xenix systems where c_cc[VMIN]
  121.  *  doesn't seem to work (even though it compiles without error!).
  122.  *
  123.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  124.  */
  125.  
  126.  
  127. #include "zmdm.h"
  128. #include "common.h"
  129. #include "zmodem.h"
  130.  
  131. static unsigned long SaveIntr;
  132.  
  133. #ifndef Vsync             /* Atari forgot these in osbind.h */
  134. #define Vsync()    xbios(37)
  135. #endif
  136.  
  137. #ifndef Supexec
  138.         /* Some versions of osbind don't define Supexec */
  139. #define Supexec(X) xbios(38,X)
  140. #endif
  141.  
  142. #if (MWC || MANX)
  143. extern FILE  *fopen();
  144. #else
  145. extern FILE  *fopen(), *fopenb();
  146. #endif
  147.  
  148. #ifndef STANDALONE
  149. #define RETURN return
  150. #else
  151. int bibis() {} /* dummy */
  152. #endif 
  153.  
  154. static long start_time;
  155.  
  156. /* called by simulated signal interrupt or terminate to clean things up */
  157. bibi(n)
  158. int n;
  159. {
  160.  
  161.     if (Zmodem)
  162.         zmputs(Attn);
  163.     canit(); mode(0);
  164.     fprintf(STDERR, "\r\nrz: caught signal %d; exiting", n);
  165.     if (fout != -1)
  166.     {
  167.         if (stfclose(fout) != 0)
  168.         {
  169.             fprintf(STDERR, "\r\nfile close ERROR\n");
  170.         }
  171.         fout = (-1);
  172.  
  173.     }
  174.  
  175. #ifdef RDEBUG
  176.     if (logf != (FILE *)NULL)
  177.         fclose(logf);
  178. #endif
  179.     aexit(128+n);
  180. }
  181.  
  182. #ifdef STANDALONE
  183. main(argc, argv)
  184. #else
  185. dorz(argc, argv)
  186. #endif /* STANDALONE */
  187. int argc;
  188. char **argv;
  189. {
  190.     register char *cp;
  191.     register int npats;
  192.     char **patts;
  193.     int exitcode;
  194.  
  195. #ifdef STANDALONE
  196. #if (MWC || MANX)
  197.     extern char *lmalloc();
  198. #endif
  199.  
  200.     /* Set up Dta */
  201.     Fsetdta(&statbuf);
  202.  
  203.     /* Get screen rez */
  204.     rez = Getrez();
  205.     drv_map = Drvmap();
  206.  
  207. #if (MWC || MANX)
  208. #ifndef DYNABUF
  209.     if((bufr = (unsigned char *)lmalloc((unsigned long)BBUFSIZ))
  210.                      == (unsigned char *)NULL)
  211. #else
  212.     if((bufr = dalloc()) == (unsigned char *)NULL)
  213. #endif /* DYNABUF */
  214.     {
  215. #ifdef REMOTE
  216.         Bauxws("Sorry, could not allocate enough memory\r\n");
  217. #else
  218.         Bconws("Sorry, could not allocate enough memory\r\n");
  219. #endif
  220.  
  221.         Pterm(4);
  222.     }
  223. #else /* MWC || MANX */
  224. #ifdef DYNABUF
  225.     if((bufr = dalloc()) == (unsigned char *)NULL)
  226.     {
  227. #ifdef REMOTE
  228.         Bauxws("Sorry, could not allocate enough memory\r\n");
  229. #else
  230.         Bconws("Sorry, could not allocate enough memory\r\n");
  231. #endif
  232.         Pterm(5);
  233.     }
  234. #endif /* DYNABUF */
  235. #endif /* MWC || MANX */
  236.  
  237. #ifndef REMOTE
  238.     STDERR = stderr;
  239. #else
  240. #ifndef DLIBS
  241.     if((STDERR = fopen("aux:", "rw")) == (FILE *)NULL)
  242.     {
  243.         Bauxws("Could not Open Aux Stream for Stderr\r\n");
  244.         finish();
  245.     }
  246.     setbuf(STDERR, (char *)NULL);
  247. #else
  248.     STDERR = stdaux;
  249. #endif /* DLIBS */
  250.     
  251. #endif /* REMOTE */
  252.  
  253.     {
  254.         int speed;
  255.         speed = getbaud();
  256.         Baudrate = BAUD_RATE(speed);
  257.         SetIoBuf();
  258.         Rsconf(speed, 0,-1,-1,-1,-1);
  259.         Vsync(); Vsync();
  260.     }
  261.  
  262. #endif /* STANDALONE */
  263.  
  264.     SendType = 0;
  265.     Rxtimeout = 100;
  266.     exitcode = 0;
  267.  
  268.     initz();
  269.  
  270. #ifndef STANDALONE
  271.     chkinvok(argv[0]);     /* if called as  'rb' set flag */
  272. #else
  273.     Progname = "rz";
  274. #endif
  275.  
  276.     npats = 0;
  277.     SaveIntr = Setexc(0x0102, -1L);
  278.     BusErr   = Setexc(2, -1L);
  279.     AddrErr  = Setexc(3, -1L);
  280.     vdebug = 0;
  281.  
  282.     while (--argc)
  283.     {
  284.         cp = *++argv;
  285.         if (*cp == '-')
  286.         {
  287.             while( *++cp)
  288.             {
  289.                 switch(*cp)
  290.                 {
  291.                 case '+':
  292.                     Lzmanag = ZMAPND; break;
  293.                 case 'B':
  294.                     ForceBinary=TRUE; break;
  295.                 case 'c':
  296.                     Crcflg=TRUE; break;
  297.                 case 'p':
  298.                     Lzmanag = ZMPROT;  break;
  299.                 case 'q':
  300.                     Quiet=TRUE; Verbose=0; break;
  301.                 case 't':
  302.                     if (--argc < 1) {
  303.                         rusage();
  304.                         RETURN(1);
  305.                     }
  306.                     Rxtimeout = atoi(*++argv);
  307.                     if (Rxtimeout<10 || Rxtimeout>1000)
  308.                     {
  309.                         rusage();
  310.                         RETURN(1);
  311.                     }
  312.                     break;
  313.                 case 'v':
  314.                     ++Verbose; break;
  315.                 default:
  316.                     rusage();
  317.                     RETURN(1);
  318.                 }
  319.             }
  320.         }
  321.         else if ( !npats && argc>0)
  322.         {
  323.             if (argv[0][0])
  324.             {
  325.                 npats=argc;
  326.                 patts=argv;
  327.             }
  328.         }
  329.     }
  330.  
  331.     if (npats > 1)
  332.     {
  333.         rusage();
  334.         RETURN(1);
  335.     }
  336.  
  337. #ifdef RDEBUG
  338.     if (Verbose > 2)
  339.     {
  340.         if ((logf = fopen(RLOGFILE, "a"))== (FILE *)NULL)
  341.         {
  342.             fprintf(STDERR, "Can't open log file %s\n",RLOGFILE);
  343.             RETURN(0200);
  344.         }
  345.         fprintf(logf, "Progname=%s\n", Progname);
  346.         vdebug = 1;
  347.     }
  348. #endif
  349.  
  350.     if ( !Quiet)
  351.     {
  352.         if (Verbose == 0)
  353.             Verbose = 2;
  354.     }
  355.  
  356.     Setexc(0x0102, bibi);
  357.  
  358.     Setexc(2, buserr);
  359.     Setexc(3, addrerr);
  360.  
  361.     if((exitcode = setjmp(abrtjmp)))
  362.     {
  363.         /* on Contrl-C */
  364.         canit();
  365.         Setexc(2, BusErr);
  366.         Setexc(3, AddrErr);
  367.         Setexc(0x0102, SaveIntr);
  368.         RETURN(exitcode);
  369.     }
  370.     
  371.     if(setjmp(busjmp))
  372.     {
  373.         /* On a bus error - instead of 2 bombs */
  374.         fprintf(STDERR,"\r\nFATAL: Bus Error\n\n");
  375. #ifdef RDEBUG
  376.         if(logf != (FILE *)NULL)
  377.             fclose(logf);
  378. #endif
  379.         if(fout != -1)
  380.         {
  381.             if (stfclose(fout) != 0)
  382.             {
  383.                 fprintf(STDERR, "\r\nfile close ERROR\n");
  384.             }
  385.             fout = (-1);
  386.         }
  387.         canit();
  388.         Setexc(2, BusErr);
  389.         Setexc(3, AddrErr);
  390.         Setexc(0x0102, SaveIntr);
  391.  
  392.         RETURN(2);
  393.     }
  394.  
  395.     if(setjmp(addrjmp))
  396.     {
  397.         /* On address error - instead of 3 bombs */
  398.         fprintf(STDERR,"\r\nFATAL: Address Error\n\n");
  399. #ifdef RDEBUG
  400.         if(logf != (FILE *)NULL)
  401.             fclose(logf);
  402. #endif
  403.         if(fout != -1)
  404.         {
  405.             if (stfclose(fout) != 0)
  406.             {
  407.                 fprintf(STDERR, "\r\nfile close ERROR\n");
  408.             }
  409.             fout = (-1);
  410.         }
  411.         canit();
  412.         Setexc(2, BusErr);
  413.         Setexc(3, AddrErr);
  414.         Setexc(0x0102, SaveIntr);
  415.  
  416.         RETURN(3);
  417.     }
  418.  
  419.     mode(1);
  420.  
  421.     if (wcreceive(npats, patts)==ERROR)
  422.     {
  423.         exitcode=0200;
  424.         canit();
  425.     }
  426.  
  427.     mode(0);
  428.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  429.         canit();
  430.  
  431. #ifdef RDEBUG
  432.     if(logf != (FILE *)NULL)
  433.         fclose(logf);
  434. #endif
  435.  
  436.     if(fout != -1)
  437.     {
  438.         if (stfclose(fout) != 0)
  439.         {
  440.             fprintf(STDERR, "\r\nfile close ERROR\n");
  441.         }
  442.         fout = (-1);
  443.     }
  444.     Setexc(2, BusErr);
  445.     Setexc(3, AddrErr);
  446.     Setexc(0x0102, SaveIntr);
  447.  
  448.      RETURN(exitcode); 
  449. }
  450.  
  451. #ifdef STANDALONE
  452. RETURN(n)
  453. int n;
  454. {
  455.     ResetIoBuf();
  456. #if (MWC || MANX)
  457. #ifndef DYNABUF
  458.     free(bufr);
  459. #else
  460.     Mfree(bufr);
  461. #endif
  462. #else
  463. #ifdef DYNABUF
  464.     Mfree(bufr);
  465. #endif
  466. #endif
  467.  
  468.     exit(n);
  469. }
  470. #endif /* STANDALONE */
  471.  
  472. rusage()
  473. {
  474.     fprintf(STDERR,
  475.         "%s for %s by ST Enthusiasts at Case Western Reserve University\n",
  476.           RSTVERSION, STOS);
  477.     fprintf(STDERR, "\tBased on %s for %s by Chuck Forsberg\n\n",
  478.         RVERSION, OS);
  479.  
  480.     fprintf(STDERR,"Usage:    rz [-Bpqtv]        (ZMODEM Batch)\n");
  481.     fprintf(STDERR,"or    rb [-qtv]        (YMODEM Batch)\n");
  482.     fprintf(STDERR,"or    rz [-cqtv] file            (XMODEM or XMODEM-1k)\n");
  483.     fprintf(STDERR,"      -B Force Binary Mode transfers\n");
  484.     fprintf(STDERR,"      -v Verbose more v's give more info\n");
  485.     fprintf(STDERR,"          -q Quiet suppresses verbosity\n");
  486.     fprintf(STDERR,"      -t TIM Change timeout to TIM tenths of seconds\n");
  487.     fprintf(STDERR,"      -c Use 16 bit CRC    (XMODEM)\n");
  488.     fprintf(STDERR,"      -p Protect existing dest. file by skipping\n");
  489.     fprintf(STDERR,"         transfer if the dest. file exists (ZMODEM ONLY)\n\n");
  490.  
  491.  
  492.     if(fout != -1)
  493.     {
  494.         if (stfclose(fout) != 0)
  495.         {
  496.             fprintf(STDERR, "\r\nfile close ERROR\n");
  497.         }
  498.         fout = (-1);
  499.     }
  500.  
  501. #ifdef RDEBUG
  502.     if(logf != (FILE *)NULL)
  503.         fclose(logf);
  504. #endif
  505.  
  506.     return(1);
  507. }
  508.  
  509.  
  510. /*
  511.  * Let's receive something already.
  512.  */
  513. wcreceive(argc, argp)
  514. int argc;
  515. char **argp;
  516. {
  517.     register int c;
  518.  
  519.     if (Batch || argc==0)
  520.     {
  521.         Crcflg=(Wcsmask==0377);
  522.         if ( !Quiet)
  523. #ifndef REMOTE
  524.             fprintf(STDERR, "\n%s: ready (CTRL-C to cancel)\n\n",
  525.                 Progname);
  526. #else
  527.             fprintf(STDERR, "\n%s: ready\n\n",
  528.                 Progname);
  529. #endif
  530.         if (c=tryz())
  531.         {
  532.             if (c == ZCOMPL)
  533.                 return OK;
  534.             if (c == ERROR)
  535.                 goto fubar;
  536.             c = rzfiles();
  537.             if (c)
  538.                 goto fubar;
  539.         }
  540.         else
  541.         {
  542.             for (;;)
  543.             {
  544.                 if (wcrxpn(secbuf)== ERROR)
  545.                     goto fubar;
  546.                 if (secbuf[0]==0)
  547.                     return OK;
  548.                 if (procheader(secbuf) == ERROR)
  549.                     goto fubar;
  550.                 if (wcrx()==ERROR)
  551.                     goto fubar;
  552.             }
  553.         }
  554.     } 
  555.     else
  556.     {
  557.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  558.  
  559.         strcpy(Pathname, *argp);
  560. #ifndef REMOTE
  561.         fprintf(STDERR, "\n%s: ready to receive %s (CTRL-C to Cancel)\n\n",
  562.             Progname, Pathname);
  563. #else
  564.         fprintf(STDERR, "\n%s: ready to receive %s\n\n",
  565.             Progname, Pathname);
  566. #endif
  567.  
  568. #ifdef RDEBUG
  569.         if(logf != (FILE *)NULL)
  570.             fprintf(logf, "\nrz: ready to receive %s ", Pathname);
  571. #endif
  572.  
  573.         if((fout = stfopen(Pathname,"w")) <= 0)
  574.             return ERROR;
  575.         if (wcrx()==ERROR)
  576.             goto fubar;
  577.     }
  578.     return OK;
  579.  
  580. fubar:
  581.     canit();
  582.  
  583.     if (fout != -1)
  584.     {
  585.         if (stfclose(fout) != 0)
  586.         {
  587.             fprintf(STDERR, "\r\nfile close ERROR\n");
  588.         }
  589.         fout = (-1);
  590.     }
  591.  
  592.     return ERROR;
  593. }
  594.  
  595.  
  596. /*
  597.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  598.  * Length is indeterminate as long as less than Blklen
  599.  * A null string represents no more files (YMODEM)
  600.  */
  601. wcrxpn(rpn)
  602. char *rpn;    /* receive a pathname */
  603. {
  604.     register int c;
  605.  
  606.     PURGELINE;
  607.  
  608. et_tu:
  609.     Firstsec=TRUE;  Eofseen=FALSE;
  610.     sendline(Crcflg?WANTCRC:NAK);
  611.     Lleft=0;    /* Do read next time ... */
  612.     while ((c = wcgetsec(rpn, 100)) != 0)
  613.     {
  614.         llog( "Pathname fetch returned %d\n", c);
  615.         if (c == WCEOT)
  616.         {
  617.             sendline(ACK);
  618.             Lleft=0;    /* Do read next time ... */
  619.             readline(1);
  620.             goto et_tu;
  621.         }
  622.         return ERROR;
  623.     }
  624.     sendline(ACK);
  625.     return OK;
  626. }
  627.  
  628. /*
  629.  * Adapted from CMODEM13.C, written by
  630.  * Jack M. Wierda and Roderick W. Hart
  631.  */
  632.  
  633. wcrx()
  634. {
  635.     register int sectnum, sectcurr;
  636.     register char sendchar;
  637.     int cblklen;            /* bytes to dump this block */
  638.  
  639.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  640.     sendchar=Crcflg?WANTCRC:NAK;
  641.  
  642.     for (;;)
  643.     {
  644.         sendline(sendchar);    /* send it now, we're ready! */
  645.         Lleft=0;    /* Do read next time ... */
  646.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  647.         report(sectcurr);
  648.         if (sectcurr==(sectnum+1 &Wcsmask))
  649.         {
  650.             sectnum++;
  651.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  652.             if (putsec(secbuf, cblklen)==ERROR)
  653.                 return ERROR;
  654.             if ((Bytesleft-=cblklen) < 0)
  655.                 Bytesleft = 0;
  656.             sendchar=ACK;
  657.         }
  658.         else if (sectcurr==(sectnum&Wcsmask))
  659.         {
  660.             log2( "Received dup Sector\n");
  661.             sendchar=ACK;
  662.         }
  663.         else if (sectcurr==WCEOT)
  664.         {
  665.             if (closeit(0L))
  666.                 return ERROR;
  667.             sendline(ACK);
  668.             Lleft=0;    /* Do read next time ... */
  669.             return OK;
  670.         }
  671.         else if (sectcurr==ERROR)
  672.             return ERROR;
  673.         else
  674.         {
  675.             log2( "Sync Error\n");
  676.             return ERROR;
  677.         }
  678.     }
  679. }
  680.  
  681.  
  682. /*
  683.  * Wcgetsec fetches a Ward Christensen type sector.
  684.  * Returns sector number encountered or ERROR if valid sector not received,
  685.  * or CAN CAN received
  686.  * or WCEOT if eot sector
  687.  * time is timeout for first char, set to 4 seconds thereafter
  688.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  689.  *    (Caller must do that when he is good and ready to get next sector)
  690.  */
  691. wcgetsec(rxbuf, maxtime)
  692. char *rxbuf;
  693. int maxtime;
  694. {
  695.     register int checksum, wcj, firstch;
  696.     register unsigned int oldcrc;
  697.     register char *p;
  698.     int sectcurr;
  699.  
  700.     for (Lastrx=errors=0; errors<RETRYMAX; errors++)
  701.     {
  702.  
  703.         if ((firstch=readline(maxtime))==STX)
  704.         {
  705.             Blklen=KSIZE; goto get2;
  706.         }
  707.         if (firstch==SOH)
  708.         {
  709.             Blklen=SECSIZ;
  710. get2:
  711.             sectcurr=readline(1);
  712.             if ((sectcurr+(oldcrc=readline(1)))==Wcsmask)
  713.             {
  714.                 oldcrc=checksum=0;
  715.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; )
  716.                 {
  717.                     if ((firstch=readline(1)) < 0)
  718.                         goto bilge;
  719.                     oldcrc=updcrc(firstch, oldcrc);
  720.                     checksum += (*p++ = firstch);
  721.                 }
  722.                 if ((firstch=readline(1)) < 0)
  723.                     goto bilge;
  724.                 if (Crcflg)
  725.                 {
  726.                     oldcrc=updcrc(firstch, oldcrc);
  727.                     if ((firstch=readline(1)) < 0)
  728.                         goto bilge;
  729.                     oldcrc=updcrc(firstch, oldcrc);
  730.                     if (oldcrc & 0xFFFF)
  731.                         llog("CRC=0%o\n", oldcrc);
  732.                     else
  733.                     {
  734.                         Firstsec=FALSE;
  735.                         return sectcurr;
  736.                     }
  737.                 }
  738.                 else if (((checksum-firstch)&Wcsmask)==0)
  739.                 {
  740.                     Firstsec=FALSE;
  741.                     return sectcurr;
  742.                 }
  743.                 else
  744.                     log2( "Checksum Error\n");
  745.             }
  746.             else
  747.                 log2("Sector number garbled 0%o 0%o\n",
  748.                  sectcurr, oldcrc);
  749.         }
  750.         /* make sure eot really is eot and not just mixmash */
  751.  
  752.         else if (firstch==EOT && Lleft==0)
  753.             return WCEOT;
  754.  
  755.         else if (firstch==CAN)
  756.         {
  757.             if (Lastrx==CAN)
  758.             {
  759.                 log2( "Sender CANcelled\n");
  760.                 return ERROR;
  761.             }
  762.             else
  763.             {
  764.                 Lastrx=CAN;
  765.                 continue;
  766.             }
  767.         }
  768.         else if (firstch==TIMEOUT)
  769.         {
  770.             if (Firstsec)
  771.                 goto humbug;
  772. bilge:
  773.             log2( "Timeout\n");
  774.         }
  775.         else
  776.             llog( "Got 0%o sector header\n", firstch);
  777.  
  778. humbug:
  779.         Lastrx=0;
  780.         while(readline(1)!=TIMEOUT)
  781.             ;
  782.         if (Firstsec)
  783.         {
  784.             sendline(Crcflg?WANTCRC:NAK);
  785.             Lleft=0;    /* Do read next time ... */
  786.         }
  787.         else
  788.         {
  789.             maxtime=40; sendline(NAK);
  790.             Lleft=0;    /* Do read next time ... */
  791.         }
  792.     }
  793.     /* try to stop the bubble machine. */
  794.     canit();
  795.     return ERROR;
  796. }
  797.  
  798.  
  799.  
  800.  
  801. /*
  802.  * Process incoming file information header
  803.  */
  804. procheader(name)
  805. char *name;
  806. {
  807.     register char  *p;
  808.     register int dot;
  809.     char openmode[4];
  810.     extern int strlen();
  811.  
  812.     /* convert to ST style path names */
  813.     for( p = name; *p != '\0'; p++)
  814.     {
  815.         if(*p == '/')
  816.             *p = '\\';
  817.     }
  818.     
  819.     /* pick out the last extention in the filename in each part of path */
  820.     while(p != name)
  821.     {
  822.         dot = 0; p-- ;
  823.         while((p != name) && (*p != '\\'))
  824.         {
  825.             if(*p == '.')
  826.             {
  827.                 if(dot == 0)
  828.                 {
  829.                     dot = 1;
  830.                 }
  831.                 else
  832.                 {
  833.                    /* replace all but the last dot with '_' */
  834.                     *p = '_';
  835.                 }
  836.             }
  837.             p--;
  838.         }
  839.     }
  840.                 
  841.     /* set default parameters and overrides */
  842.     strcpy(openmode,"w");
  843.  
  844.     Thisbinary = isbinary(name);
  845.  
  846.     if (Lzmanag)
  847.         zmanag = Lzmanag;
  848.  
  849.     /*
  850.      *  Process ZMODEM remote file management requests
  851.      */
  852.     if ( zconv == ZCNL)    /* Remote ASCII override */
  853.         Thisbinary = 0;
  854.     if (zconv == ZCBIN)    /* Remote Binary override */
  855.         ++Thisbinary;
  856.     else if (zmanag == ZMAPND)
  857.         strcpy(openmode, "a");
  858.  
  859.     if (ForceBinary == TRUE )    /* local binary force override */
  860.         ++Thisbinary;
  861.  
  862.     /* ZMPROT check for existing file */
  863.     if (zmanag == ZMPROT && existf(name, "r"))
  864.     {
  865.         return ERROR;
  866.     }
  867.  
  868. /* ATARI ST NOTE:
  869.  *    We will not accept rooted paths ie. paths that begin in '\' or '.\'
  870.  *    If the incoming filename is rooted, we skip the beginning
  871.  *    '\'   '.\'  or  '..\'
  872.  */
  873.  
  874.     if( (name[0] == '\\') || (name[0] == '.')  )
  875.     {
  876.         /* skip over the leading stuff */
  877.         if(name[0] == '\\')
  878.             name = &name[1];
  879.         else
  880.         {
  881.             if(name[1] == '.')
  882.                 name = &name[3];  /* Skip the "..\" */
  883.             else
  884.                 name = &name[2];  /* Skip the ".\"  */
  885.         }
  886.     }
  887.  
  888.     /* ST addition, create any dierctories in the path that don't exist */
  889.     if( pathensure(name) == ERROR)
  890.         return ERROR;
  891.  
  892.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  893.  
  894.     p = name + 1 + strlen(name);
  895.     if (*p)
  896.     {    /* file coming from Unix or DOS system */
  897.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  898. /* NA to atari
  899.             if (Filemode & UNIXFILE)
  900.                 ++Thisbinary; 
  901. */
  902. #ifndef REMOTE
  903.         if (Verbose)
  904.         {
  905.             fprintf(STDERR,
  906.             "\nIncoming:\n\tName:\t%s\n\tBytes:\t%ld\n\
  907. \tModTime: %ld\n\tMode:\t%o\n\tBufSize: %ld\n\n",
  908.               name, Bytesleft, Modtime, Filemode, (long)BBUFSIZ);
  909.  
  910. #ifdef RDEBUG
  911.             if(logf != (FILE *)NULL)
  912.                 fprintf(logf,  "Incoming: %s %ld %lo %o\n",
  913.                   name, Bytesleft, Modtime, Filemode);
  914. #endif
  915.  
  916.         }
  917. #endif /* REMOTE */
  918.  
  919.     }
  920.     else
  921.     {        /* File coming from CP/M system */
  922.         for (p=name; *p; ++p)        /* change / to _ */
  923.             if ( *p == '/')
  924.                 *p = '_';
  925.  
  926.         if ( *--p == '.')        /* zap trailing period */
  927.             *p = 0;
  928.     }
  929.     
  930.     strcpy(Pathname, name);
  931. #ifndef REMOTE
  932.     if (Verbose)
  933.     {
  934.         fprintf(STDERR,  "Receiving %s %s [mode %s]\n\n",
  935.           name, Thisbinary?"BIN":"ASCII", openmode);
  936.  
  937. #ifdef RDEBUG
  938.         if(logf != (FILE *)NULL)
  939.             fprintf(logf,  "Receiving %s %s %s\n",
  940.               name, Thisbinary?"BIN":"ASCII", openmode);
  941. #endif
  942.  
  943.     }
  944. #endif /* REMOTE */
  945.  
  946.     if ((fout=stfopen(name, openmode)) <= 0)
  947.         return ERROR;
  948.  
  949.     return OK;
  950. }
  951.  
  952. /*
  953.  * Putsec writes the n characters of buf to receive file fout.
  954.  *  If not in binary mode,  all characters
  955.  *  starting with CPMEOF are discarded.
  956.  */
  957. putsec(buf, n)
  958. unsigned char *buf;
  959. register int n;
  960. {
  961.     register unsigned char *p;
  962.  
  963.     if (Thisbinary)
  964.     {
  965.         for (p=buf; --n>=0; p++ )
  966.         {
  967.             if(stputc( *p, fout) < 0)
  968.             {
  969.                 fprintf(STDERR, "\r\nError while Writing file\n");
  970.                 return ERROR;
  971.             }
  972.         }
  973.     }
  974.     else
  975.     {
  976.         if (Eofseen)
  977.             return OK;
  978.  
  979.         for (p=buf; --n>=0; p++ )
  980.         {
  981.             if (*p == CPMEOF)
  982.             {
  983.                 Eofseen=TRUE;
  984.                 return OK;
  985.             }
  986.             if(*p == '\n')
  987.             {
  988.                 if(stputc('\r' ,fout) < 0)
  989.                 {
  990.                     fprintf(STDERR, "\r\nError while Writing file\n");
  991.                     return ERROR;
  992.                 }
  993.             }
  994.             if(stputc(*p ,fout) < 0)
  995.             {
  996.                 fprintf(STDERR,"\r\nError while Writing file\n");
  997.                 return ERROR;
  998.             }
  999.         }
  1000.     }
  1001.  
  1002.     return OK;
  1003. }
  1004.  
  1005. /*
  1006.  * Log an error only if high verbose
  1007.  */
  1008. /*VARARGS1*/
  1009. llog(s,p,u)
  1010. char *s;
  1011. int p, u;
  1012. {
  1013.     if (Verbose < 3)
  1014.         return;
  1015. #ifdef RDEBUG
  1016.     fprintf(logf, "error %d: ", errors);
  1017.     fprintf(logf, s, p, u);
  1018. #endif
  1019.  
  1020.     fprintf(STDERR, "\nerror %d: ", errors);
  1021.     fprintf(STDERR, s, p, u);
  1022. }
  1023.  
  1024.  
  1025.  
  1026. #ifndef STANDALONE
  1027. /*
  1028.  * If called as rb use YMODEM protocol
  1029.  */
  1030. chkinvok(s)
  1031. char *s;
  1032. {
  1033.     Progname = s;
  1034.     if (s[0]=='r' && s[1]=='b')
  1035.         Nozmodem = TRUE;
  1036. }
  1037. #endif
  1038.  
  1039. /*
  1040.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1041.  *  Handles ZSINIT frame
  1042.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1043.  *   ZCOMPL if transaction finished,  else 0
  1044.  */
  1045. tryz()
  1046. {
  1047.     register int n;
  1048.     register int cmdzack1flg;
  1049.  
  1050.     if (Nozmodem)        /* Check for "rb" program name */
  1051.         return 0;
  1052.  
  1053.  
  1054.     for (n=Zmodem?10:5; --n>=0; )
  1055.     {
  1056.         /* Set buffer length (0) and capability flags */
  1057.         stohdr(0L);
  1058.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; /* of course we can break */
  1059.  
  1060.         zshhdr(tryzhdrtype, Txhdr);
  1061. /*        zshhdr(Badclose?ZFERR:ZRINIT, Txhdr); */
  1062. again:
  1063.         switch (zgethdr(Rxhdr, 0))
  1064.         {
  1065.         case ZRQINIT:
  1066.             continue;
  1067.         case ZEOF:
  1068.             continue;
  1069.         case TIMEOUT:
  1070.             continue;
  1071.         case ZFILE:
  1072.             zconv = Rxhdr[ZF0];
  1073.             zmanag = Rxhdr[ZF1];
  1074.             ztrans = Rxhdr[ZF2];
  1075.             tryzhdrtype = ZRINIT;
  1076.             Badclose = FALSE;
  1077.             if (zrdata(secbuf, KSIZE) == GOTCRCW)
  1078.                 return ZFILE;
  1079.             zshhdr(ZNAK, Txhdr);
  1080.             goto again;
  1081.         case ZSINIT:
  1082.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW)
  1083.             {
  1084.                 zshhdr(ZACK, Txhdr);
  1085.                 goto again;
  1086.             }
  1087.             zshhdr(ZNAK, Txhdr);
  1088.             goto again;
  1089.         case ZFREECNT:
  1090.             stohdr(~0L);
  1091.             zshhdr(ZACK, Txhdr);
  1092.             goto again;
  1093.         case ZCOMMAND:
  1094.             cmdzack1flg = Rxhdr[ZF0];
  1095.             if (zrdata(secbuf, KSIZE) == GOTCRCW)
  1096.             {
  1097.                 if (cmdzack1flg & ZCACK1)
  1098.                     stohdr(0L);
  1099.                 else
  1100.                     stohdr((long)sys2(secbuf));
  1101.                 PURGELINE;    /* dump impatient questions */
  1102.                 do {
  1103.                     zshhdr(ZCOMPL, Txhdr);
  1104.                 }
  1105.                 while (++errors<10 && zgethdr(Rxhdr,1) != ZFIN);
  1106.                 ackbibi();
  1107.                 if (cmdzack1flg & ZCACK1)
  1108.                     exec2(secbuf);
  1109.                 return ZCOMPL;
  1110.             }
  1111.             zshhdr(ZNAK, Txhdr); goto again;
  1112.         case ZCOMPL:
  1113.             goto again;
  1114.         default:
  1115.             continue;
  1116.         case ZFIN:
  1117.             ackbibi(); return ZCOMPL;
  1118.         case ZCAN:
  1119.             return ERROR;
  1120.         }
  1121.     }
  1122.     return 0;
  1123. }
  1124.  
  1125. /*
  1126.  * Receive 1 or more files with ZMODEM protocol
  1127.  */
  1128. rzfiles()
  1129. {
  1130.     register int c;
  1131.  
  1132.     for (;;) {
  1133.         switch (c = rzfile()) {
  1134.         case ZEOF:
  1135.         case ZSKIP:
  1136.             switch (tryz()) {
  1137.             case ZCOMPL:
  1138.                 return OK;
  1139.             default:
  1140.                 return ERROR;
  1141.             case ZFILE:
  1142.                 break;
  1143.             }
  1144.             continue;
  1145.         default:
  1146.             return c;
  1147.         case ERROR:
  1148.             return ERROR;
  1149.         }
  1150.     }
  1151. }
  1152.  
  1153. /*
  1154.  * Receive a file with ZMODEM protocol
  1155.  *  Assumes file name frame is in secbuf
  1156.  */
  1157. rzfile()
  1158. {
  1159.     register int c, n;
  1160.     long rxbytes;
  1161.     extern void rd_time();
  1162.  
  1163.     Eofseen=FALSE;
  1164.     if (procheader(secbuf) == ERROR) {
  1165.         return (tryzhdrtype = ZSKIP);
  1166. /*        zshhdr(ZSKIP, Txhdr);
  1167.         return ZSKIP; */
  1168.     }
  1169.  
  1170.     n = 10; rxbytes = 0L;
  1171.  
  1172.     Supexec(rd_time);
  1173.     start_time = pr_time;
  1174.  
  1175.     for (;;)
  1176.     {
  1177.         stohdr(rxbytes);
  1178.         zshhdr(ZRPOS, Txhdr);
  1179. nxthdr:
  1180.         switch (c = zgethdr(Rxhdr, 0)) {
  1181.         default:
  1182.             vfile("rzfile: zgethdr returned %d", c);
  1183.             return ERROR;
  1184.         case ZNAK:
  1185.         case TIMEOUT:
  1186.             if ( --n < 0)
  1187.             {
  1188.                 vfile("rzfile: zgethdr returned %d", c);
  1189.                 return ERROR;
  1190.             }
  1191.         case ZFILE:
  1192.             zrdata(secbuf, KSIZE);
  1193.             continue;
  1194.         case ZEOF:
  1195.             /* ++jrb */
  1196.             if (rclhdr(Rxhdr) != rxbytes)
  1197.             {
  1198.                 /*
  1199.                      * Ignore eof if it's at wrong place - force
  1200.                      *  a timeout because the eof might have gone
  1201.                      *  out before we sent our zrpos.
  1202.                      */
  1203.  
  1204.                     errors = 0;  goto nxthdr;
  1205.             }
  1206. /* --jrb
  1207.             if (rclhdr(Rxhdr) != rxbytes)
  1208.             {
  1209.                 continue;
  1210.             }
  1211. -- */
  1212.             if (closeit(rxbytes))
  1213.             {
  1214.                 tryzhdrtype = ZFERR;
  1215.                 Badclose = TRUE;
  1216.                 vfile("rzfile: closeit returned <> 0");
  1217.                 return ERROR;
  1218.             }
  1219.             vfile("rzfile: normal EOF");
  1220.             return c;
  1221.         case ERROR:    /* Too much garbage in header search error */
  1222.             if ( --n < 0)
  1223.             {
  1224.                 vfile("rzfile: zgethdr returned %d", c);
  1225.                 return ERROR;
  1226.             }
  1227.             zmputs(Attn);
  1228.             continue;
  1229.         case ZDATA:
  1230.             n = 10;
  1231.             if (rclhdr(Rxhdr) != rxbytes)
  1232.             {
  1233.                 zmputs(Attn);
  1234.                 continue;
  1235.             }
  1236. moredata:
  1237.             switch (c = zrdata(secbuf, KSIZE))
  1238.             {
  1239.             case ZCAN:
  1240.                 vfile("rzfile: zgethdr returned %d", c);
  1241.                 return ERROR;
  1242.             case ERROR:    /* CRC error */
  1243.                 if ( --n < 0)
  1244.                 {
  1245.                     vfile("rzfile: zgethdr returned %d", c);
  1246.                     return ERROR;
  1247.                 }
  1248.                 zmputs(Attn);
  1249.                 continue;
  1250.             case TIMEOUT:
  1251.                 if ( --n < 0)
  1252.                 {
  1253.                     vfile("rzfile: zgethdr returned %d", c);
  1254.                     return ERROR;
  1255.                 }
  1256.                 continue;
  1257.             case GOTCRCW:
  1258.                 if(putsec(secbuf, Rxcount) == ERROR)
  1259.                     return ERROR;
  1260.                 rxbytes += Rxcount;
  1261.                 lreport(rxbytes);
  1262.                 stohdr(rxbytes);
  1263.                 zshhdr(ZACK, Txhdr);
  1264.                 goto nxthdr;
  1265.             case GOTCRCQ:
  1266.                 if(putsec(secbuf, Rxcount) == ERROR)
  1267.                     return ERROR;
  1268.                 rxbytes += Rxcount;
  1269.                 lreport(rxbytes);
  1270.                 stohdr(rxbytes);
  1271.                 zshhdr(ZACK, Txhdr);
  1272.                 goto moredata;
  1273.             case GOTCRCG:
  1274.                 if(putsec(secbuf, Rxcount) == ERROR)
  1275.                     return ERROR;
  1276.                 rxbytes += Rxcount;
  1277.                 lreport(rxbytes);
  1278.                 goto moredata;
  1279.             case GOTCRCE:
  1280.                 if(putsec(secbuf, Rxcount) == ERROR)
  1281.                     return ERROR;
  1282.                 rxbytes += Rxcount;
  1283.                 lreport(rxbytes);
  1284.                 goto nxthdr;
  1285.             }
  1286.         }
  1287.     }
  1288. }
  1289.  
  1290. /*
  1291.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1292.  *   and \335 (break signal)
  1293.  */
  1294. zmputs(s)
  1295. char *s;
  1296. {
  1297.     register int c;
  1298.  
  1299.     while (*s) {
  1300.         switch (c = *s++) {
  1301.         case '\336':
  1302.             stsleep(1); continue;
  1303.         case '\335':
  1304.             sendbrk(); continue;
  1305.         default:
  1306.             sendline(c);
  1307.         }
  1308.     }
  1309. }
  1310.  
  1311.  
  1312.  
  1313. /*
  1314.  * Close the receive dataset, return OK or ERROR
  1315.  */
  1316. closeit(rxbytes)
  1317. long rxbytes;
  1318. {
  1319.     unsigned int timep[2];
  1320.     long end_time;
  1321.     extern void rd_time();
  1322.  
  1323.     if (stfclose(fout) != 0) {
  1324.         fprintf(STDERR, "\r\nfile close ERROR\n");
  1325.         return ERROR;
  1326.     }
  1327.     fout = (-1);
  1328.  
  1329.     Supexec(rd_time);
  1330.     end_time = pr_time;
  1331.  
  1332.     if (Modtime) {
  1333.         unix2st(Modtime, &timep[0], &timep[1]);
  1334.         touch(Pathname, timep);
  1335.     }
  1336.  
  1337.     /* if it is read only by owner on remote, then it is set
  1338.      * to read only on the ST, all other file modes are
  1339.      * irrelevant.
  1340.      */
  1341.     if (Filemode)
  1342.     {
  1343.         unsigned int fmode;
  1344.  
  1345.         fmode = (unsigned int)(Filemode & 000777);
  1346.         if( ((fmode & 0200) == 0) && ((fmode & 0400) != 0) )
  1347.         {
  1348.             /* it is readonly by owner on the remote, so
  1349.              * make it read only on the ST too
  1350.              */
  1351.             Fattrib(Pathname, 1, 0x01);
  1352.         }
  1353.     }
  1354. #ifndef REMOTE
  1355.     if(rxbytes != 0L)
  1356.         fprintf(STDERR,"\n\n%s Closed\nTransfer Time %ld secs.\tfor %ld bytes\
  1357. \tApprox %ld cps\n\n", Pathname, (end_time - start_time)/200L, rxbytes,
  1358. rxbytes/((end_time - start_time)/200L));
  1359.     else
  1360.         fprintf(STDERR,"\n\n%s Closed\n\n", Pathname);
  1361. #endif
  1362.     lsct = 1;
  1363.     return OK;
  1364. }
  1365.  
  1366. /*
  1367.  * Ack a ZFIN packet, let byegones be byegones
  1368.  */
  1369. ackbibi()
  1370. {
  1371.     register int n;
  1372.  
  1373.     vfile("ackbibi:");
  1374.     Readnum = 1;
  1375.     stohdr(0L);
  1376.     for (n=4; --n>=0; )
  1377.     {
  1378.         zshhdr(ZFIN, Txhdr);
  1379.         for (;;) {
  1380.             switch (readline(100))
  1381.             {
  1382.             case 'O':
  1383.                 readline(1);    /* Discard 2nd 'O' */
  1384.                 /* ***** FALL THRU TO ***** */
  1385.             case TIMEOUT:
  1386.                 vfile("ackbibi complete");
  1387.                 return;
  1388.             default:
  1389.                 break;
  1390.             }
  1391.         }
  1392.     }
  1393. }
  1394.  
  1395.  
  1396. /*
  1397.  * Strip leading ! if present, do shell escape. 
  1398.  */
  1399. sys2(s)
  1400. register char *s;
  1401. {
  1402.     if (*s == '!')
  1403.         ++s;
  1404.     return stsystem(s);
  1405. }
  1406. /*
  1407.  * Strip leading ! if present, do exec.
  1408.  */
  1409. exec2(s)
  1410. char *s;
  1411. {
  1412. /** Are you kidding
  1413.     if (*s == '!')
  1414.         ++s;
  1415.     mode(0);
  1416.     execl("/bin/sh", "sh", "-c", s); 
  1417. **/
  1418. }
  1419.  
  1420. /*
  1421.  * Touch a file
  1422.  */
  1423. #ifndef MANX
  1424. #undef Fdatime        /* There exist brain damaged versions of osbind.h */
  1425. #define    Fdatime(a,b,c)    gemdos(0x57,a,b,c)
  1426. #endif /* MANX has its _Gemdos stuff */
  1427.  
  1428. touch(name, timep)
  1429. char *name;
  1430. unsigned int *timep;
  1431. {
  1432.     register int handl;
  1433.  
  1434.     if((handl = Fopen(name, 0)) < 0)
  1435.     {
  1436. #ifndef REMOTE
  1437.         fprintf(STDERR,"*WARNING* Could not set file modification time for %s\n",
  1438.             name);
  1439. #endif
  1440.         return;
  1441.     }
  1442.  
  1443.  
  1444.     Fdatime(timep, handl, 1);
  1445.     Fclose(handl);
  1446. }
  1447.  
  1448. /* -eof- */
  1449.